這邊來認識一些我們可能會用到的一些資料庫查詢操作
根據前面的 products 結構來插入一些資料熟悉一些操作的用法吧。
INSERT INTO products (name, price, description) VALUES
('薩爾達傳說:曠野之息', 59.99, '設定在幻想世界中的開放世界動作冒險遊戲。'),
('超級瑪利歐:奧德賽', 49.99, '以瑪利歐為主角的平臺遊戲,探索各種世界。'),
('集合啦!動物森友會', 54.99, '在無人島上進行發展的生活模擬遊戲。'),
('最終幻想 VII 重製版', 69.99, '經典 RPG 的重製版,具有更新的圖像和遊戲玩法。'),
('巫師3:狂獵', 39.99, '開放世界 RPG,玩家扮演狩魔獵人傑洛特。'),
('電馭叛客2077', 59.99, '設定在反烏托邦未來世界的開放世界 RPG。'),
('對馬戰鬼', 59.99, '設定在日本封建時代的動作冒險遊戲。'),
('碧血狂殺2', 49.99, '以西部為主題的開放世界動作冒險遊戲。'),
('黑帝斯', 24.99, '在地下城中進行逃脫的類 Roguelike 遊戲。'),
('我們之中', 4.99, '在太空船上進行的多人派對遊戲,涉及團隊合作與背叛。');
前面一篇有提到可以直接透過欄位名稱來查找,JPA會自動幫我們對應,最常用到的就是 findById,如果想要查找其他欄位就可以直接改成像是 findByName, findByPrice 等等都可以讓 JPA 幫我們匹配。
這邊根據 findByName 我們可以透過名稱找到對應商品
controller
    @GetMapping("/q")
    public Product getProductsByName(@RequestParam String name) {
        return productService.getProductByName(name);
    }
service
@Service
public class ProductService {
    @Autowired
    private ProductRepository productRepository;
    public Product getProductByName(String name) {
        return productRepository.findByName(name);
    }
}
repository
public interface ProductRepository extends JpaRepository<Product, Integer> {
    Product findByName(String name);
}

可以根據數值的範圍來進行查詢,像是這邊可以用價錢來進行示範
他的格式會像 findBy{判斷欄位}GreaterThanEqual()
findByPriceGreaterThan()
findByPriceGreaterThanEqual()
findByPriceLessThan()
findByPriceLessThanEqual()
這邊用大於等於
controller
    @GetMapping("/priceGreaterThanEqual")
    public List<Product> getProductsByPriceGreaterThanEqual(@RequestParam int range) {
        return productService.getProductGreaterThanEqual(range);
    }
service
@Service
public class ProductService {
    @Autowired
    private ProductRepository productRepository;
    public List<Product> getProductGreaterThanEqual(int range) {
        return productRepository.findByPriceGreaterThanEqual(range);
    }
}
repository
@Repository
public interface ProductRepository extends JpaRepository<Product, Integer> {
    Product findByName(String name);
    List<Product> findByPriceGreaterThanEqual(int range);
}
查詢大於 60 元剛好只有 69.99 元的最終幻想符合
可透過 And 或 Or 組合
controller
    @GetMapping("/nameOrPrice")
    public List<Product> getProductsByNameOrPrice(@RequestParam String name, @RequestParam double price) {
        return productService.getProductByNameOrPrice(name, price);
    }
service
    public List<Product> getProductByNameOrPrice(String name, double price) {
        return productRepository.findByNameOrPrice(name, price);
    }
repository
@Repository
public interface ProductRepository extends JpaRepository<Product, Integer> {
    List<Product> findByNameOrPrice(String name, double price);
}

or 的話只要其中一項條件符合就會執行,像是下面有搜出 name = 黑帝斯 也有搜出 price = 49.99
使用 JPA 如果不夠彈性你也可使用原生的語法 @Query
@Query 裡面要第一個參數註明是 nativeQuery = true , 第二個參數是 vlaue = “{sql 語法}” ,也可以把 value 省略,直接用 SQL 字串放第二個參數,注意這邊 SQL 語法結尾請不要加分號 “;”
參數的帶入也可以用 :param 的方式,這邊其實寫法有很多種,大家就找到自己喜歡或是團隊易懂的方式來撰寫。
*如果 nativeQuery 沒有開啟就是使用 JPQL
//    用 """ """ 可以不用顧慮換行問題
//    @Query(
//            nativeQuery = true,
//            value = """
//                SELECT *
//                FROM `products`
//                WHERE `name` = ?1 OR `price` = ?2
//            """
//    )
		// JPQL 須注意如果語法長中間可能換行及空格導致語法錯誤
		@Query("SELECT p FROM Product p WHERE p.name = :name OR p.price = :price")
		// Native SQL 須注意如果語法長中間可能換行及空格導致語法錯誤
    @Query(
            nativeQuery = true,
            value = "SELECT * FROM products WHERE name = ?1 OR price = ?2"
    )
    List<Product> findByNameOrPriceNative(String name, double price);
利用 Sort 物件可以做到排序,看是要升序(ASC)或是降序(DESC),這個物件是可以直接帶入 repository 的方法中告知 JPA 要進行排序
// asc
Sort sort = Sort.by({欄位}).ascending() 
// desc
Sort sort = Sort.by({欄位}).descending();
以撈出全部資料 Service 方法為例,根據價錢進行升序
    public List<Product> getAllProducts() {
        Sort sort = Sort.by("price").ascending();
        return productRepository.findAll(sort);
    }
可以看到顯示資料就照價錢由小到大排了

Sort 也可以整合下面分頁物件一起做到排序及分頁
Pageabe 是一個介面,通常會放入三個參數來透過 PageRequest 方法實作
Pageable pageable = PageRequest.of(page, limit, sort);
把上面的 Sort 物件一起帶進去,並且告知我要取得第一頁的 3 筆資料
public Page<Product> getAllProducts() {
        Sort sort = Sort.by("price").ascending();
        Pageable pageable = PageRequest.of(0,3, sort);
        Page<Product> productPage = productRepository.findAll(pageable);
        return productPage;
    }
回傳的資料可以看到確實有排序,還有提供分頁的相關資訊,也只顯示出第一頁的 3 筆資料
{
    "content": [
        {
            "id": 4,
            "name": "最終幻想 VII 重製版",
            "price": 69.99,
            "description": "經典 RPG 的重製版,具有更新的圖像和遊戲玩法。"
        },
        {
            "id": 1,
            "name": "薩爾達傳說:曠野之息",
            "price": 59.99,
            "description": "設定在幻想世界中的開放世界動作冒險遊戲。"
        },
        {
            "id": 6,
            "name": "電馭叛客2077",
            "price": 59.99,
            "description": "設定在反烏托邦未來世界的開放世界 RPG。"
        }
    ],
    "pageable": {
        "pageNumber": 0,
        "pageSize": 3,
        "sort": {
            "empty": false,
            "sorted": true,
            "unsorted": false
        },
        "offset": 0,
        "paged": true,
        "unpaged": false
    },
    "totalPages": 4,
    "totalElements": 10,
    "last": false,
    "size": 3,
    "number": 0,
    "sort": {
        "empty": false,
        "sorted": true,
        "unsorted": false
    },
    "numberOfElements": 3,
    "first": true,
    "empty": false
}
以上就是基本的一些查詢跟應用,對於許多網站的搜尋及資料的查找都是相當基本的用法,Spring Data Jpa 也提供給我們許多方便的用法,還有一定的彈性可以自行撰寫原生 SQL。那下篇來講一些關於資料庫關聯的一些操作介紹吧。
Ref:
相關文章也會同步更新我的部落格,有興趣也可以在裡面找其他的技術分享跟資訊。